package com.aplikata.evok.ui;

import java.io.Serializable;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;

import org.primefaces.context.RequestContext;
import org.primefaces.event.DateSelectEvent;
import org.primefaces.event.ScheduleEntryMoveEvent;
import org.primefaces.event.ScheduleEntryResizeEvent;
import org.primefaces.event.ScheduleEntrySelectEvent;
import org.primefaces.event.SelectEvent;
import org.primefaces.model.DefaultScheduleEvent;
import org.primefaces.model.LazyScheduleModel;
import org.primefaces.model.ScheduleEvent;
import org.primefaces.model.ScheduleModel;

import com.aplikata.bo.Node;
import com.aplikata.bo.UserEvent;
import com.aplikata.constants.Constants;
import com.aplikata.evok.bo.DoctorSchedule;
import com.aplikata.evok.bo.DomainPatient;
import com.aplikata.evok.bo.Patient;
import com.aplikata.evok.constants.EvokConstants;
import com.aplikata.evok.datamodel.DoctorScheduleDataModel;
import com.aplikata.evok.email.EvokEmailUtil;
import com.aplikata.evok.service.EvokDoctorService;
import com.aplikata.ui.UIBean;
import com.aplikata.util.FacesUtil;
import com.aplikata.util.YunDateUtil;

/**
 * @ClassName: EvokDoctorScheduleBean
 * @Description: TODO
 * @author Huyun
 * @date Sep 6, 2012 12:47:03 PM
 */
@ManagedBean(name = "doctorScheduleBean")
@ViewScoped
public class EvokDoctorScheduleBean extends UIBean {

	private static final long serialVersionUID = 1L;

	@ManagedProperty(value = "#{evokDoctorService}")
	private EvokDoctorService doctorService;
	private ScheduleModel lazyEventModel;
	private ScheduleEvent sEvent = new DefaultScheduleEvent();
	private UserEvent uEvent;
	private int eventAmount;
	private DoctorScheduleDataModel todayModel;
	private DoctorSchedule[] selectedSchedules;

	private String header;
	private DoctorSchedule doctorSchedule;

	private Integer calendarType;
	private String qyPatientName;
	private Long qyDomainPatientId;
	private DataModel<Object[]> therapyModel = new ListDataModel<Object[]>();
	private Object[] therapyObj;

	@PostConstruct
	public void init() {
		doctorSchedule = new DoctorSchedule(EvokConstants.DOC_RESERVATION_STATUS_NORMAL);
		uEvent = new UserEvent(getSessionUser());
	}

	public ScheduleModel getLazyEventModel() {
		if (lazyEventModel == null) {
			lazyEventModel = new LazyScheduleModel() {

				private static final long serialVersionUID = 1L;

				@Override
				public void loadEvents(Date start, Date end) {
					clear();
					List<ScheduleEvent> list = doctorService
							.findDoctorAllCalendar(getSessionUser().getId(), start, end);

					if (list == null || list.isEmpty())
						return;

					for (ScheduleEvent event : list) {
						this.addEvent(event);
					}
				}
			};
		}
		return lazyEventModel;
	}

	public void onDateSelect(DateSelectEvent selectEvent) {
		sEvent = new DefaultScheduleEvent("", selectEvent.getDate(), selectEvent.getDate());
		calendarType = null;
		qyPatientName = null;
		doctorSchedule = new DoctorSchedule(EvokConstants.DOC_RESERVATION_STATUS_NORMAL);
		doctorSchedule.setTimeFrom(selectEvent.getDate());
		doctorSchedule.setTimeTo(selectEvent.getDate());
		
		uEvent = new UserEvent();
		uEvent.setTimeFrom(selectEvent.getDate());
		uEvent.setTimeTo(selectEvent.getDate());
		qyDomainPatientId = null;
		therapyObj = null;
	}

	public void onEventSelect(ScheduleEntrySelectEvent selectEvent) {
		sEvent = selectEvent.getScheduleEvent();
		Object obj = sEvent.getData();

		if (obj instanceof UserEvent) {
			calendarType = EvokConstants.CALENDAR_TYPE_OTHER;
			uEvent = (UserEvent) obj;
			doctorSchedule = new DoctorSchedule(EvokConstants.DOC_RESERVATION_STATUS_NORMAL);
		} else if (obj instanceof DoctorSchedule) {
			calendarType = EvokConstants.CALENDAR_TYPE_PATIENT;
			uEvent = new UserEvent(getSessionUser());
			doctorSchedule = (DoctorSchedule) obj;
			Patient patient = doctorSchedule.getDomainPatient().getPatient();
			qyDomainPatientId = doctorSchedule.getDomainPatient().getId();
			qyPatientName = patient.getSurname() + " " + patient.getName() + " "
					+ YunDateUtil.formatDate(patient.getBirthday()) + " " + qyDomainPatientId;
			if (doctorSchedule.getPatientTherapy() == null) {
				therapyObj = null;
			} else {
				therapyObj = doctorService.getTherapyObjForCalendar(doctorSchedule.getPatientTherapy().getId());
			}
		}
	}

	public void submitEventAction() {
		RequestContext context = RequestContext.getCurrentInstance();
		boolean therapyError = false;

		try {
			doctorService.updateDoctorSchedule(getSessionUser(), getSessionUser(), calendarType, uEvent, doctorSchedule,
					qyDomainPatientId, therapyObj);
			
			if(EvokConstants.CALENDAR_TYPE_PATIENT == calendarType.intValue() && doctorSchedule.getStatus() != null
					&& doctorSchedule.getStatus().intValue() == EvokConstants.DOC_RESERVATION_STATUS_CANCEL)
				EvokEmailUtil.sendReservationEmail(doctorSchedule.getDomainPatient().getPatient().getId(), doctorSchedule, doctorSchedule.getStatus());
			
			todayModel = null;
			todayModel = this.getTodayModel();
		} catch (Exception e) {
			FacesUtil.addActionListenerException(e, log);
			therapyError = true;
			context.addCallbackParam("therapyError", therapyError);
		}
	}

	public String goTherapyAction() {
		FacesContext.getCurrentInstance().getExternalContext().getFlash()
				.put(EvokConstants.FLASH_SCHEDULE, doctorSchedule);
		FacesContext.getCurrentInstance().getExternalContext().getFlash()
				.put(EvokConstants.FLASH_SCHEDULE_DOMAIN_PATIENT, doctorSchedule.getDomainPatient());
		FacesContext.getCurrentInstance().getExternalContext().getFlash()
				.put(EvokConstants.FLASH_PATIENT_THERAPY, doctorSchedule.getPatientTherapy());
		Node node = (Node) doctorService.findSingleByProperty(Node.class, Node.DESCRIPTION,
				EvokConstants.PAGE_PATIENT_THERAPY);
		FacesUtil.setManagedBeanInSession(Constants.SESSION_SELECTED_MENU, node);
		return EvokConstants.PAGE_PATIENT_THERAPY;
	}

	public String linkAction() {
		doctorSchedule = todayModel.getRowData();
		FacesContext.getCurrentInstance().getExternalContext().getFlash()
				.put(EvokConstants.FLASH_SCHEDULE, doctorSchedule);
		FacesContext.getCurrentInstance().getExternalContext().getFlash()
				.put(EvokConstants.FLASH_SCHEDULE_DOMAIN_PATIENT, doctorSchedule.getDomainPatient());
		FacesContext.getCurrentInstance().getExternalContext().getFlash()
				.put(EvokConstants.FLASH_PATIENT_THERAPY, doctorSchedule.getPatientTherapy());

		Node node = (Node) doctorService.findSingleByProperty(Node.class, Node.DESCRIPTION,
				EvokConstants.PAGE_PATIENT_THERAPY);
		FacesUtil.setManagedBeanInSession(Constants.SESSION_SELECTED_MENU, node);
		return EvokConstants.PAGE_PATIENT_THERAPY;
	}

	public void finishTodayAllAction() {
		if (selectedSchedules == null) {
			return;
		}

		try {
			doctorService.updateFinishTodayReservation(selectedSchedules);
			todayModel = null;
			todayModel = this.getTodayModel();
		} catch (Exception e) {
			FacesUtil.addActionListenerException(e, log);
		}
	}

	public void deleteEvent() {
		try {
			if (sEvent.getData() != null) {
				Object obj = sEvent.getData();
				doctorService.delete((Serializable) obj);
				
				if(EvokConstants.CALENDAR_TYPE_PATIENT == calendarType.intValue())
					EvokEmailUtil.sendReservationEmail(doctorSchedule.getDomainPatient().getPatient().getId(), doctorSchedule, EvokConstants.DOC_RESERVATION_STATUS_CANCEL);
				
				lazyEventModel = null;
				lazyEventModel = this.getLazyEventModel();
				todayModel = null;
				todayModel = this.getTodayModel();
				sEvent = new DefaultScheduleEvent();
			}
		} catch (Exception e) {
			FacesUtil.addActionListenerException(e, log);
		}
	}

	public void onEventMove(ScheduleEntryMoveEvent event) {
		try {
			uEvent = (UserEvent) event.getScheduleEvent().getData();
			doctorService.merge(uEvent);
			lazyEventModel = null;
			lazyEventModel = this.getLazyEventModel();
		} catch (Exception e) {
			FacesUtil.addActionListenerException(e, log);
		}
	}

	public void onEventResize(ScheduleEntryResizeEvent event) {
		try {
			uEvent = (UserEvent) event.getScheduleEvent().getData();
			doctorService.merge(uEvent);
			lazyEventModel = null;
			lazyEventModel = this.getLazyEventModel();
		} catch (Exception e) {
			FacesUtil.addActionListenerException(e, log);
		}
	}

	public void setLazyEventModel(ScheduleModel lazyEventModel) {
		this.lazyEventModel = lazyEventModel;
	}

	public ScheduleEvent getsEvent() {
		return sEvent;
	}

	public void setsEvent(ScheduleEvent sEvent) {
		this.sEvent = sEvent;
	}

	public UserEvent getuEvent() {
		return uEvent;
	}

	public void setuEvent(UserEvent uEvent) {
		this.uEvent = uEvent;
	}

	public int getEventAmount() {
		eventAmount = ((BigInteger) doctorService.findSingleByNamedQuery("UserEvent.findUndoAmount",
				new Object[] { FacesUtil.getUserFromSession().getId() })).intValue();
		return eventAmount;
	}

	public void setEventAmount(int eventAmount) {
		this.eventAmount = eventAmount;
	}

	public EvokDoctorService getDoctorService() {
		return doctorService;
	}

	public void setDoctorService(EvokDoctorService doctorService) {
		this.doctorService = doctorService;
	}

	public DoctorSchedule getDoctorSchedule() {
		if (FacesUtil.isKeyNull(doctorSchedule.getStatus())) {
			doctorSchedule.setStatus(EvokConstants.DOC_RESERVATION_STATUS_NORMAL);
		}
		return doctorSchedule;
	}

	public void setDoctorSchedule(DoctorSchedule doctorSchedule) {
		this.doctorSchedule = doctorSchedule;
	}

	public String getHeader() {
		header = FacesUtil.getMessage("patient_reservations") + " " + YunDateUtil.formatDateTime("dd/MM/yyyy");
		return header;
	}

	public void setHeader(String header) {
		this.header = header;
	}

	public String getQyPatientName() {
		return qyPatientName;
	}

	public void setQyPatientName(String qyPatientName) {
		this.qyPatientName = qyPatientName;
	}

	@SuppressWarnings("unchecked")
	public List<String> completeQueryName(String query) {
		return (List<String>) doctorService.findByNamedQuery(DomainPatient.QY_FIND_NAME,
				new Object[] { this.getQyDomainId(), query + "%" });
	}

	public void selectPatientName(SelectEvent event) {
		qyPatientName = (String) event.getObject();
		String idString = qyPatientName.substring(qyPatientName.lastIndexOf(" "), qyPatientName.length());
		qyDomainPatientId = Long.parseLong(idString.trim());
	}

	public void openTherapyListAction() {
		if (FacesUtil.isKeyNull(qyDomainPatientId)) {
			therapyModel = new ListDataModel<Object[]>();
			return;
		}

		List<?> qyTherapyList = doctorService.getPatientTherapyListForCanlendar(qyDomainPatientId);
		therapyModel.setWrappedData(qyTherapyList);
	}

	public void chooseTherapyAction() {
		therapyObj = (Object[]) therapyModel.getRowData();
	}

	public void deleteTherapyAction() {
		therapyObj = null;
	}

	public DataModel<Object[]> getTherapyModel() {
		return therapyModel;
	}

	public void setTherapyModel(DataModel<Object[]> therapyModel) {
		this.therapyModel = therapyModel;
	}

	public Object[] getTherapyObj() {
		return therapyObj;
	}

	public void setTherapyObj(Object[] therapyObj) {
		this.therapyObj = therapyObj;
	}

	public Integer getCalendarType() {
		return calendarType;
	}

	public void setCalendarType(Integer calendarType) {
		this.calendarType = calendarType;
	}

	public void setTodayModel(DoctorScheduleDataModel todayModel) {
		this.todayModel = todayModel;
	}

	public DoctorScheduleDataModel getTodayModel() {
		if (todayModel == null) {
			List<DoctorSchedule> list = doctorService
					.getDoctorTodayResversation(FacesUtil.getUserFromSession().getId());
			todayModel = new DoctorScheduleDataModel(doctorService, list);
		}

		return todayModel;
	}

	public DoctorSchedule[] getSelectedSchedules() {
		return selectedSchedules;
	}

	public void setSelectedSchedules(DoctorSchedule[] selectedSchedules) {
		this.selectedSchedules = selectedSchedules;
	}
}
